#include "gd32f30x.h"
#include "string.h"
#include "stdint.h"
#include "stdio.h"

#include "DevicesQueue.h"
#include "DevicesSoftTimer.h"
#include "DevicesUID.h"
#include "DevicesCRC.h"

#include "uip.h"
#include "tapdev.h"
#include "uip_arp.h"
#include "timer.h"
#include "dhcps.h"

#include "taskNetworkConnect.h"
#include "taskNetwork.h"


#define BUF ((struct uip_eth_hdr *)&uip_buf[0])

/* 网络超时时间 */
struct timer periodic_timer, arp_timer;


void vTaskNetwork(void *pvParameters)
{
    uip_ipaddr_t typeIpAddr;
    int32_t i = 0;

    /* 网卡驱动初始化 */
    tapdev_init();

    /* uIP初始化 */
    uip_init();

    /* 设置本机IP地址 */
    uip_ipaddr(typeIpAddr, IP_ADDR0_LOCAL, IP_ADDR1_LOCAL, IP_ADDR2_LOCAL, IP_ADDR3_LOCAL);
    uip_sethostaddr(typeIpAddr);

    /* 设置路由器IP地址 */
    uip_ipaddr(typeIpAddr, IP_ADDR0_LOCAL, IP_ADDR1_LOCAL, IP_ADDR2_LOCAL, IP_ADDR3_LOCAL);
    uip_setdraddr(typeIpAddr);

    /* 设置网络掩码 */
    uip_ipaddr(typeIpAddr, 255, 255, 255, 0);
    uip_setnetmask(typeIpAddr);

    /* 网络超时时间 */
    timer_set(&periodic_timer, 100);
    timer_set(&arp_timer, 10000);

    /* DHCP服务端 */
    dhcps_init();

    while (1)
    {
        memset(uip_buf, 0, sizeof(uip_buf));

        uip_len = tapdev_read();
        if(uip_len > 0)
        {
            if(BUF->type == htons(UIP_ETHTYPE_IP))
            {
                uip_arp_ipin();
                uip_input();
                /* If the above function invocation resulted in data that
                should be sent out on the network, the global variable
                uip_len is set to a value > 0. */
                if(uip_len > 0)
                {
                    uip_arp_out();
                    tapdev_send();
                }
            }
            else if(BUF->type == htons(UIP_ETHTYPE_ARP))
            {
                uip_arp_arpin();
                /* If the above function invocation resulted in data that
                should be sent out on the network, the global variable
                uip_len is set to a value > 0. */
                if(uip_len > 0)
                {
                    tapdev_send();
                }
            }
        }
        else if(timer_expired(&periodic_timer))
        {
            timer_reset(&periodic_timer);

            for(i = 0; i < UIP_CONNS; i++)
            {
                uip_periodic(i);
                /* If the above function invocation resulted in data that
                should be sent out on the network, the global variable
                uip_len is set to a value > 0. */
                if(uip_len > 0)
                {
                    uip_arp_out();
                    tapdev_send();
                }
            }

            /* Call the ARP timer function every 10 seconds. */
            if(timer_expired(&arp_timer))
            {
                timer_reset(&arp_timer);
                uip_arp_timer();
            }
        }

#if UIP_UDP
        for(i = 0; i < UIP_UDP_CONNS; i++)
        {
            uip_udp_periodic(i);
            /* If the above function invocation resulted in data that
            should be sent out on the network, the global variable
            uip_len is set to a value > 0. */
            if(uip_len > 0)
            {
                uip_arp_out();
                tapdev_send();
            }
        }
#endif /* UIP_UDP */
    }
}


void UIP_APPCALL(void)
{
    int32_t iLength = 0;

    if(uip_flags != UIP_POLL)
    {
        printf("UIP_APPCALL: 0x%02X.\r\n", uip_flags);
        printf("UIP remote IP: %d, %d, %d, %d lport: %d rport: %d.\r\n", uip_conn->ripaddr[0] & 0xFF, uip_conn->ripaddr[0] >> 8, uip_conn->ripaddr[1] & 0xFF, uip_conn->ripaddr[1] >> 8, HTONS(uip_conn->lport), HTONS(uip_conn->rport));
    }

    if(uip_acked())
    {
        printf("uip_acked.\r\n\n");
    }

    if(uip_newdata())
    {
        printf("uip_newdata.\r\n");
        printf("UIP receive length: %d data: %s\r\n\n", uip_len, (char *)uip_appdata);
        ((char *)uip_appdata)[uip_len] = 0;
    }

    if(uip_rexmit())
    {
        printf("uip_rexmit.\r\n\n");
        uip_send("uip_rexmit.\r\n", strlen("uip_rexmit.\r\n"));
    }

    if(uip_connected())
    {
        printf("uip_connected.\r\n\n");
    }

    if(uip_closed())
    {
        printf("uip_closed.\r\n\n");
        g_ptypeUipConnectHandle[0] = NULL;
    }

    if(uip_aborted())
    {
        printf("uip_aborted.\r\n\n");
        uip_close();
        g_ptypeUipConnectHandle[0] = NULL;
    }

    if(uip_timedout())
    {
        printf("uip_conn->timer: %d\r\n", uip_conn->timer);
        printf("uip_timedout.\r\n\n");
        g_ptypeUipConnectHandle[0] = NULL;
    }

    if(uip_poll())
    {
        if((iLength = iQueueGetLengthOfOccupy(&g_TypeQueueNetworkTcp1Send)) != 0)
        {
            iLength = iLength > UIP_APPDATA_SIZE ? UIP_APPDATA_SIZE : iLength;

            /* 直接使用uIP数据缓存 */
            extern void *uip_sappdata;
            enumQueuePopDatas(&g_TypeQueueNetworkTcp1Send, uip_sappdata, iLength);

            uip_send(uip_sappdata, iLength);
        }
    }
}

void UIP_UDP_USERCALL(void)
{
    int32_t iLength = 0;

    if(uip_flags != UIP_POLL)
    {
        printf("UIP_UDP_APPCALL: 0x%02X.\r\n", uip_flags);
        printf("UIP remote IP: %d, %d, %d, %d lport: %d rport: %d.\r\n", uip_udp_conn->ripaddr[0] & 0xFF, uip_udp_conn->ripaddr[0] >> 8, uip_udp_conn->ripaddr[1] & 0xFF, uip_udp_conn->ripaddr[1] >> 8, HTONS(uip_udp_conn->lport), HTONS(uip_udp_conn->rport));
    }

    if(uip_acked())
    {
        printf("uip_acked.\r\n\n");
    }

    if(uip_newdata())
    {
        printf("uip_newdata.\r\n");
        printf("UIP receive length: %d data: %s\r\n\n", uip_len, (char *)uip_appdata);
        ((char *)uip_appdata)[uip_len] = 0;
    }

    if(uip_rexmit())
    {
        printf("uip_rexmit.\r\n\n");
        uip_send("uip_rexmit.\r\n", strlen("uip_rexmit.\r\n"));
    }

    if(uip_connected())
    {
        printf("uip_connected.\r\n\n");
    }

    if(uip_closed())
    {
        printf("uip_closed.\r\n\n");
    }

    if(uip_aborted())
    {
        printf("uip_aborted.\r\n\n");
        uip_abort();
    }

    if(uip_timedout())
    {
        printf("uip_timedout.\r\n\n");
        uip_abort();
    }

    if(uip_poll())
    {
        if((iLength = iQueueGetLengthOfOccupy(&g_TypeQueueNetworkUdp1Send)) != 0)
        {
            iLength = iLength > UIP_APPDATA_SIZE ? UIP_APPDATA_SIZE : iLength;

            /* 直接使用uIP数据缓存 */
            extern void *uip_sappdata;
            enumQueuePopDatas(&g_TypeQueueNetworkUdp1Send, uip_sappdata, iLength);

            uip_send(uip_sappdata, iLength);
        }
    }
}

void UIP_UDP_APPCALL(void)
{
    switch(HTONS(uip_udp_conn->lport))
    {
        /* DHCP 服务端 端口号 */
        case DHCPC_SERVER_PORT: dhcps_appcall(); break;
        /* DHCP 客户端 端口号 */
        case DHCPC_CLIENT_PORT: dhcpc_appcall(); break;

        /* 普通消息 端口号 */
        default : UIP_UDP_USERCALL(); break;
    }
}
